<script setup lang="ts">


import {ref, reactive, toRaw} from "vue";
import {executeSql,executeNextSql,executeCloseSql} from "@/views/api/elastic.ts"

import {Download, Search,VideoPause} from "@element-plus/icons-vue";
const formRef = ref<FormInstance>();
import {ScrollResult} from "@/views/types/elastic-type.ts";
import {FormInstance,FormRules} from "element-plus";
import {error,confirm} from "@/utils/message.ts";
import JsonView from "@/components/JsonView.vue";
import JsonText from "@/components/JsonText.vue";
import FilterColumns from "@/views/components/FilterColumns.vue";

const isDownloading = ref(false);
const isShowSelectColumn = ref(false);
const filterColumns = reactive([]);
const errors = reactive({});
const isShowError = ref(false);
const loading = ref(false);
const executing = ref(false);
const canceling = ref(false);
const cursor = ref("");
const index = ref(-1);
const result = ref<ScrollResult>({});
interface Column {
  align: string,
  label: string,
  prop: string,
  width: number,
}
const onColumnChange = (values) => {
  filterColumns.splice(0, filterColumns.length);
  values.forEach(column => {
    filterColumns.push({
      align: "center",
      label: column,
      prop: column,
      width: 180,
    })
  })
}
const columns = ref<Array<Column>>([]);
const list = ref<Array<Object>>([]);
const execute = () =>{
  formRef.value?.validate().then(v => {
    if(v){
      index.value=1;
      filterColumns.splice(0, filterColumns.length);
      loading.value=true;
      executeSql(form.value.query,form.value.size).then(scrollResult=>{
        result.value=scrollResult;
        cursor.value=result.value.cursor;
        list.value=[];
        columns.value=[];
        if(result.value && result.value.columns && result.value.columns.length > 0){
          columns.value.push(...result.value.columns.map(value => {
            return {
              align: "center",
              label: value.name,
              prop: value.name,
              width: 180,
            }
          }))
          filterColumns.push(...result.value.columns.map(value => {
            return {
              align: "center",
              label: value.name,
              prop: value.name,
              width: 180,
            }
          }))
        }
        if(result.value && result.value.rows && result.value.rows.length > 0){
          result.value.rows.forEach(array=>{
            let row={};
            for (let index = 0; index < array.length; index++) {
              let key=columns.value[index].prop
              row[key]=array[index];
            }
            list.value.push(row);
          })
          if(result.value.cursor){
            if(form.value.isFetch){
              executeNext();
            }else{
              confirm("信息提示","已完成" +index.value +"次查询,是否继续查询下一页?").then(()=>{
                executeNext();
              }).catch(()=>{
                cancel();
              })
            }
          }else{
            loading.value = false ;
          }
        }else{
          loading.value = false ;
        }

      }).catch((err) => {
        loading.value=false;
        Object.keys(errors).forEach(key => {
          delete errors[key];
        })
        if (err?.response?.data) {
          Object.assign(errors, err?.response?.data);
          isShowError.value = true;
        } else {
          error(err.message);
        }

      })
    }
  })
}
const downloadExcel = () => {
  let headers = filterColumns.map(column => column.prop);
  let rows = toRaw(list.value);
  let filename = `sql-${new Date().getTime()}.xlsx`;
  isDownloading.value = true;
  window.api.openSaveFolder(filename).then(res => {
    let canceled = res.canceled
    if (!canceled) {
      window.api.export.excel(res.filePath, '', headers, rows).then(res => {
        console.log("下载完成", res);
      }).catch(err => {
        console.log("下载失败", err);
      }).finally(() => {
        isDownloading.value = false;
      })
    } else {
      isDownloading.value = false;
    }
  }).catch(() => {
    isDownloading.value = false;
  })
}
const cancel = () =>{
  if(cursor.value){
    canceling.value=true;
    executeCloseSql(cursor.value).then(()=>{
      executing.value = false;
      loading.value=false;
    }).finally(()=>{
      canceling.value=false;
    })
  }
}
const executeNext= () =>{
  if(cursor.value && !canceling.value){
    executing.value = true;
    executeNextSql(cursor.value).then(res=>{
      index.value=index.value+1;
      if(res.rows && res.rows.length > 0){
        cursor.value=res.cursor;
        result.value.cursor=res.cursor;
        res.rows.forEach(array=>{
          let row={};
          for (let index = 0; index < array.length; index++) {
            let key=columns.value[index].prop
            row[key]=array[index];
          }
          list.value.push(row);
          result.value.rows.push(array);
        })
        if(form.value.isFetch){
          executeNext();
        }else{
          confirm("信息提示","已完成" +index.value +"次查询,是否继续查询下一页?").then(()=>{
            executeNext();
          }).catch(()=>{
            cancel();
          })
        }
      }else{
        cancel();
      }
    })
  }else{
    loading.value=false;
  }
}
interface QueryForm{
  query:string;
  size:number;
  isFetch:boolean;
}

const form = ref<QueryForm>({
  query:"",
  size:100,
  isFetch:false,
})

//@ts-ignore
const rules = reactive<FormRules<QueryForm>>({
  query: [
    { required: true, message: "sql为必填项", trigger: ["blur", "change"] }
  ],
  size: [
    { required: true,type:"number", message: "批次大小为必填项", trigger: ["blur", "change"] }
  ]
});
</script>

<template>
  <div>
    <JsonView v-if="isShowError" v-model:visible="isShowError" title="错误信息" v-model="errors"></JsonView>
    <el-form  ref="formRef"
              :model="form"
              :rules="rules">
      <el-row>
        <el-col :span="8">
          <el-form-item prop="size" label="批次大小">
            <el-input-number v-model="form.size" ></el-input-number>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item prop="isFetch" label="自动加载">
            <el-checkbox v-model="form.isFetch" title="数据较多时,会较为卡顿,不建议使用" ></el-checkbox>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item style="width:100%;">
            <div style="width:100%;display: flex;justify-content: space-between;">
              <div>
                <span v-if="index>0 && loading">正在进行第 {{ index }} 次查询,共计查询到 {{list.length}} 条数据</span>
                <span v-if="index>0 && !loading">已完成 {{ index }} 次查询,共计查询到 {{list.length}} 条数据</span>
              </div>
              <div>
                <el-button type="primary" v-if="!executing"  @click="execute" :loading="loading" :disabled="!form.query" :icon="Search" >搜 索</el-button>
                <el-button   v-else  @click="cancel" :icon="VideoPause" :loading="canceling">停 止</el-button>
              </div>
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item prop="query">
            <el-input  type="textarea" v-model="form.query" :rows="12" placeholder="请输入sql" spellcheck="false"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <el-tabs>
      <el-tab-pane label="表格">
        <div style="display:flex;justify-content: flex-end;margin: 5px">
          <el-button-group>
            <FilterColumns :visible="isShowSelectColumn" :columns="columns" :filter-columns="filterColumns" :disabled="Object.keys(filterColumns).length===0" @change="onColumnChange"></FilterColumns>
            <el-button text :loading="isDownloading" :icon="Download" :disabled="Object.keys(result).length===0" @click="downloadExcel"></el-button>
          </el-button-group>
        </div>
        <el-table :data="list" stripe border height="450">
          <el-table-column label="序号" type="index" fixed="left" width="80px" align="center" v-if="Object.keys(filterColumns).length!==0">

          </el-table-column>
          <template v-for="column in filterColumns">
            <el-table-column sortable :prop="column.prop" :label="column.label" :min-width="column.width" :align="column.align" show-overflow-tooltip/>
          </template>
        </el-table>
      </el-tab-pane>
      <el-tab-pane label="JSON">
        <div style="height: 450px;padding: 2px;border: solid 1px var(--el-border-color);">
          <JsonText :value="result"></JsonText>
        </div>
      </el-tab-pane>
    </el-tabs>

  </div>
</template>

<style scoped>

</style>